package com.ruicar.afs.cloud.bizcommon.cfca.service.Impl;

import cfca.paperless.client.bean.*;
import cfca.paperless.client.servlet.PaperlessClient;
import cfca.paperless.client.util.*;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.XML;
import com.itextpdf.text.pdf.PdfReader;
import com.ruicar.afs.cloud.bizcommon.cfca.dto.CfCaSignatureDto;
import com.ruicar.afs.cloud.bizcommon.cfca.enums.LocationTypeEnum;
import com.ruicar.afs.cloud.bizcommon.cfca.service.CfCaSignatureService;
import com.ruicar.afs.cloud.bizcommon.cfca.untils.CfCaConfig;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

import static com.ruicar.afs.cloud.bizcommon.cfca.untils.CfCaConstants.*;

/**
 * @ClassName CfCaSignatureServiceImpl
 * @Description: cfca签名
 * @Author mingzhi.li
 * @Date 2020/8/7
 * @Version V1.0
 **/
@Slf4j
@Service
@Component
@AllArgsConstructor
public class CfCaSignatureServiceImpl implements CfCaSignatureService {
    private CfCaConfig cfCaConfig;

    @Override
    public byte[] getCfCaSignature(CfCaSignatureDto dto) throws Exception {
        // 开始时间
        long timeStart = System.currentTimeMillis();
        log.info("签章开始时间"+timeStart);
        //设置请求连接时长
        PaperlessClient clientBean = new PaperlessClient(cfCaConfig.getCfcaUrl(), 10000, 60000);
        byte[] handwritingImage = mergeApplyAppPicture(dto.getFile(),dto.getRotationAngle());
        ImageUtil.resizeImage(handwritingImage, 20, 20);
        List<MultiDataBean> list = new ArrayList<MultiDataBean>();
        //手写签名图片
        list.add(new MultiDataBean(handwritingImage, dto.getCustId()+".png", SIGN_TYPE));
        String[] proofHashAndMultiData = PaperlessUtil.getProofHashAndMultiData(list);
        SignLocation signLocation = new SignLocation(1, dto.getKeyword(), "R", 0, 0);
        SealUserInfo sealUserInfo = new SealUserInfo(dto.getCustName(), "Z", dto.getCertNo(), dto.getTelPhone(), dto.getDetailAddress(), SEAL_REASON);
        // 设置印章显示大小，可以不设置。比如：100，代表100px。比如需要把章显示为4cm（圆章且DPI为96）时，传入151即可。（并且imageScale配置为0.87）
        sealUserInfo.setSealImageSize(20);
        String proofSealStrategyXml = StrategyUtil.createProofSealStrategyXml(handwritingImage, sealUserInfo, signLocation, proofHashAndMultiData[0]);
        log.info("签约合同文件处理开始");
        //20200813测试注释
        byte[] pdfFile = dto.getFileByte();
        String compoundSealStrategyXml = "<List>" + proofSealStrategyXml +  "</List>";
        //签名信息
        String multiData = "[" + proofHashAndMultiData[1] + "]";
        //这个参数客户也不知道啥意思
        String bizTypeCode = "";
        PdfBean pdfBean = new PdfBean(Base64.toBase64String(pdfFile), bizTypeCode);
        String pdfBeanXml = PaperlessUtil.buildPdfBeanXml(pdfBean);
        String channelBeanXml = new ChannelBean(CHANNEL_CODE).toString();
        String pdfBeanListXml = "<List>" + pdfBeanXml +  "</List>";
        String signPdf = clientBean.compoundSealAutoPdfListDetached(pdfBeanListXml,multiData,compoundSealStrategyXml,CHANNEL_CODE,channelBeanXml,SCENE_CERT_CHANNEL, TIMES_TAMP_CHANNEL);
        JSONObject xmlJSONObj = XML.toJSONObject(signPdf);
        JSONObject codeObject = xmlJSONObj.getJSONObject("Result");
        Integer code = (Integer) codeObject.get("Code");
        if(code !=200){
            log.info((String) codeObject.get("Message"));
            return new byte[0];
        }
        JSONObject object = xmlJSONObj.getJSONObject("Result").getJSONObject("List").getJSONObject("PdfBean");
        String sealedPdf = (String) object.get("Pdf");
        String errorRsString = PaperlessUtil.isError(Base64.decode(sealedPdf));
        if (StrUtil.isBlank(errorRsString)) {
            //无任何异常信息
            log.info("=========签约成功==========》");
            return Base64.decode(sealedPdf);
        } else {
            log.info("=========签约失败==========》》失败原因："+errorRsString);
            return null;
        }
    }

    /**
     * 手写签名图片合成
     * @param file
     * @param rotationAngle
     * @return
     */
    public byte[] mergeApplyAppPicture (String [] file,int rotationAngle){
        int type = 1;
        int len = file.length;
        File[] src = new File[len];
        BufferedImage[] images = new BufferedImage[len];
        int[][] ImageArrays = new int[len][];
        for (int i = 0; i < len; i++) {
            try {
                if(rotationAngle >0 ){
                    images[i] = Rotate(ImageIO.read(new ByteArrayInputStream(Base64.decode(file[i]))),rotationAngle);
                }else{
                    images[i] = ImageIO.read(new ByteArrayInputStream(Base64.decode(file[i])));
                }

            } catch (Exception e) {
                e.printStackTrace();
                return new byte[0];
            }
            int width = images[i].getWidth();
            int height = images[i].getHeight();
            // 从图片中读取RGB
            ImageArrays[i] = new int[width * height];
            ImageArrays[i] = images[i].getRGB(0, 0, width, height, ImageArrays[i], 0, width);
        }
        int newHeight = 0;
        int newWidth = 0;
        for (int i = 0; i < images.length; i++) {
            //横向
            if(type == 1){
                newHeight = newHeight > images[i].getHeight() ? newHeight : images[i].getHeight();
                newWidth += images[i].getWidth();
            }else if(type == 2){
                //纵向
                newWidth = newWidth > images[i].getWidth() ? newWidth : images[i].getWidth();
                newHeight += images[i].getHeight();
            }
        }
        log.info("拼接后图像宽度："+newWidth);
        log.info("拼接后图像高度："+newHeight);
        if (type == 1 && newWidth < 1) {
            log.info("拼接后图像宽度小于1");
            return new byte[0];
        }
        if (type == 2 && newHeight < 1) {
            log.info("拼接后图像高度小于1");
            return new byte[0];
        }
        //生成新图片
        try {
            BufferedImage ImageNew = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
            int height_i = 0;
            int width_i = 0;
            for (int i = 0; i < images.length; i++) {
                if(type == 1){
                    ImageNew.setRGB(width_i, 0, images[i].getWidth(), newHeight, ImageArrays[i], 0, images[i].getWidth());
                    width_i += images[i].getWidth();
                }else if(type == 2){
                    ImageNew.setRGB(0, height_i, newWidth, images[i].getHeight(), ImageArrays[i], 0, newWidth);
                    height_i += images[i].getHeight();
                }
            }
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            // 图片写入到输出流中
            ImageIO.write(ImageNew, "png", out);
            return out.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new byte[0];
    }

    /**
     * 对图片进行旋转
     *
     * @param src   被旋转图片
     * @param angel 旋转角度
     * @return 旋转后的图片
     */
    public static BufferedImage Rotate(Image src, int angel) {
        int srcWidth = src.getWidth(null);
        int srcHeight = src.getHeight(null);
        // 计算旋转后图片的尺寸
        Rectangle rectDes = CalcRotatedSize(new Rectangle(new Dimension(
                srcWidth, srcHeight)), angel);
        BufferedImage res = null;
        res = new BufferedImage(rectDes.width, rectDes.height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics2D = res.createGraphics();
        // 进行转换
        graphics2D.translate((rectDes.width - srcWidth) / 2, (rectDes.height - srcHeight) / 2);
        graphics2D.rotate(Math.toRadians(angel), srcWidth / 2, srcHeight / 2);

        graphics2D.drawImage(src, null, null);
        return res;
    }
    /**
     * 计算旋转后的图片
     *
     * @param src   被旋转的图片
     * @param angel 旋转角度
     * @return 旋转后的图片
     */
    public static Rectangle CalcRotatedSize(Rectangle src, int angel) {
        // 如果旋转的角度大于90度做相应的转换
        if (angel >= 90) {
            if (angel / 90 % 2 == 1) {
                int temp = src.height;
                src.height = src.width;
                src.width = temp;
            }
            angel = angel % 90;
        }

        double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
        double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
        double angelAlpha = (Math.PI - Math.toRadians(angel)) / 2;
        double angelDaltaWidth = Math.atan((double) src.height / src.width);
        double angelDaltaHeight = Math.atan((double) src.width / src.height);

        int lenDaltaWidth = (int) (len * Math.cos(Math.PI - angelAlpha - angelDaltaWidth));
        int lenDaltaHeight = (int) (len * Math.cos(Math.PI - angelAlpha - angelDaltaHeight));
        int desWidth = src.width + lenDaltaWidth * 2;
        int desHeight = src.height + lenDaltaHeight * 2;
        return new Rectangle(new Dimension(desWidth, desHeight));
    }

    /**
     * PC端创建电子签章合同模板
     * @param dto
     * @param file
     * @return
     * @throws Exception
     */
    @Override
    public byte[] getCfCaSealCompanySign(CfCaSignatureDto dto, File file) {

        try {
            log.info("签章开始时间"+System.currentTimeMillis());
            PaperlessClient clientBean = new PaperlessClient(cfCaConfig.getCfcaUrl(), 10000, 60000);
            // 如下为加盖机构印章的策略，如果没用机构印章此处可以省略
            log.info("=========加盖机构印章的策略开始==========》》");
            SignLocation signLocation = new SignLocation(KEY_WORD, "C", 20, 20);
            SealUserInfo sealUserInfo = new SealUserInfo(dto.getCustName(), dto.getDetailAddress(), SEAL_REASON);
            String sealStrategyXml = StrategyUtil.createSealStrategyXml(SIGN_CODE, SEAL_PASSWORD, sealUserInfo, signLocation);
            byte[] pdfFile = FileUtil.readBytes(file);
            String compoundSealStrategyXml = "<List>" +sealStrategyXml +  "</List>";
            PdfBean pdfBean = new PdfBean(Base64.toBase64String(pdfFile), "");
            String pdfBeanXml = PaperlessUtil.buildPdfBeanXml(pdfBean);

            String channelBeanXml = new ChannelBean(CHANNEL_CODE).toString();
            String systemNo = GUID.generateId();
            //企业公章：multiDate为空：但是不能为null
            byte[] sealedPdf = clientBean.compoundSealAutoPdf(systemNo,pdfBeanXml, "", compoundSealStrategyXml, SEAL_GWMGY, channelBeanXml, SCENE_CERT_CHANNEL, TIMES_TAMP_CHANNEL);
            String errorRsString = PaperlessUtil.isError(sealedPdf);
            if (StrUtil.isBlank(errorRsString)) {
                log.info("=========加盖机构印章结束==========》》");
                return sealedPdf;
            } else {
                log.info("=========加盖机构印章异常==========》》异常原因："+errorRsString);
                return null;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
    /**
     * PC端创建电子签章合同模板
     * @param dto
     * @param file
     * @return file
     * @throws Exception
     */
    @Override
    public File signCfCaSealCompanySeal(CfCaSignatureDto dto, File file) {
        try {
            log.info("签章开始时间"+System.currentTimeMillis()+"文件名字"+file.getName());
            PaperlessClient clientBean = new PaperlessClient(cfCaConfig.getCfcaUrl(), 10000, 60000);
            // 如下为加盖机构印章的策略，如果没用机构印章此处可以省略
            log.info("=========加盖机构印章的策略开始==========》》");
            SignLocation signLocation = null;
            if(dto.getLocationType().equals(AfsEnumUtil.key(LocationTypeEnum.KEYWORD))){
                signLocation= new SignLocation(dto.getKeyword(), "C", 0, 0);
            }
            if(dto.getLocationType().equals(AfsEnumUtil.key(LocationTypeEnum.COORDINATE))){
                PdfReader pdfReader = new PdfReader(new FileInputStream(file));
                int pages = pdfReader.getNumberOfPages();
                signLocation= new SignLocation(pages, pages,dto.getCoordinateX().intValue() , dto.getCoordinateY().intValue());
            }
            String sealPassword=dto.getSealPassword()==null?SEAL_PASSWORD:dto.getSealPassword();
            SealUserInfo sealUserInfo = new SealUserInfo(dto.getAffiliatedInstitutions(), dto.getAffiliatedInstitutions(), dto.getApplyNo());
            String sealStrategyXml = StrategyUtil.createSealStrategyXml(dto.getSealNo(), sealPassword, sealUserInfo, signLocation);
            byte[] pdfFile = FileUtil.readBytes(file);
            String compoundSealStrategyXml = "<List>" +sealStrategyXml +  "</List>";
            PdfBean pdfBean = new PdfBean(Base64.toBase64String(pdfFile), "");
            String pdfBeanXml = PaperlessUtil.buildPdfBeanXml(pdfBean);
            String channelBeanXml = new ChannelBean(CHANNEL_CODE).toString();
            //企业公章：multiDate为空：但是不能为null
            byte[] sealedPdf = clientBean.compoundSealAutoPdf(GUID.generateId(), pdfBeanXml, "", compoundSealStrategyXml, SEAL_GWMGY, channelBeanXml, SCENE_CERT_CHANNEL, TIMES_TAMP_CHANNEL);
            String errorRsString = PaperlessUtil.isError(sealedPdf);
            Assert.isTrue(StrUtil.isBlank(errorRsString),"=========加盖机构印章异常==========》》异常原因："+errorRsString);
            log.info("=========加盖机构印章结束==========》》");
            File outFile = FileUtil.writeBytes(sealedPdf,file);
            return outFile;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}
